package spass.raytracer;

import java.util.List;

import javax.inject.Inject;

import org.springframework.stereotype.Service;

import spass.geometry.Point;
import spass.geometry.Ray;
import spass.renderer.Color;
import spass.renderer.PixelRenderer;
import spass.scene.Scene;
import spass.scene.SceneObject;
import spass.scene.forms.Intersection;
import spass.scene.light.DirectionalLight;

@Service
public class RayTracer {

    private final EyeRayCreator eyeRayCreator;
    private final ShadowDetector shadowDetector;

    @Inject
    RayTracer(EyeRayCreator eyeRayCreator, ShadowDetector shadowDetector) {
        this.eyeRayCreator = eyeRayCreator;
        this.shadowDetector = shadowDetector;
    }

    public void render(Scene scene, PixelRenderer renderer) {
        int width = renderer.getWidth();
        int height = renderer.getHeight();

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                renderPixel(scene, renderer, x, y);
            }
        }
    }

    private void renderPixel(Scene scene, PixelRenderer renderer, int x, int y) {
        Ray eyeRay = eyeRayCreator.createRay(renderer, x, y);

        SceneObject compositeSceneObject = scene.getCompositeSceneObject();
        Intersection closestIntersection = compositeSceneObject.closestIntersection(eyeRay);

        if (closestIntersection != null) {
            Color renderColor = getColorToRender(scene, closestIntersection);

            renderer.setImagePixel(x, y, renderColor);
        }
    }

    private Color getColorToRender(Scene scene, Intersection intersection) {
        SceneObject closestObject = intersection.getObject();
        List<SceneObject> otherObjects = scene.getObjectsExcept(closestObject);

        Point intersectionPoint = intersection.getPoint();
        DirectionalLight directionalLight = scene.getDirectionalLight();
        double shadow = shadowDetector.detectShadowAt(intersectionPoint, otherObjects, directionalLight);

        Color objectColor = closestObject.colorInDirectionalLightAt(intersection, directionalLight);
        Color renderColor = objectColor.scale(1 - shadow);

        return renderColor;
    }

}
